﻿// Copyright (c) Vitaly Kamiansky. All rights reserved. 
// See License.txt in the project root.

using System;
using System.ComponentModel;

namespace Property.Workers
{
    public class FunctionWorker<T> : Worker
    {
        protected FunctionWorker(IWorkerPrototype workerPrototype, Func<T> getValue)
        {
            if (workerPrototype == null) throw new ArgumentNullException("workerPrototype");
            if (getValue == null) throw new ArgumentNullException("getValue");

            _WorkerPrototype = workerPrototype;
            _GetValue = getValue;

            SetNewWorker();
        }

        //=//

        private readonly IWorkerPrototype _WorkerPrototype;
        private readonly Func<T> _GetValue;

        private IWorker WorkerState;

        public override bool IsBusy {  get { return WorkerState.IsBusy; } }

        public override void RunWorkerAsync()
        {
            if (WorkerState.IsBusy)
                ResetWorker();
            WorkerState.RunWorkerAsync();
        }

        private void ResetWorker()
        {
            DisposeWorker();
            SetNewWorker();
        }

        private void SetNewWorker()
        {
            WorkerState = _WorkerPrototype.Create();

            if (WorkerState == null)
                throw new NotSupportedException(StringsCallbacks.CANT_OBTAIN_WORKER);

            WorkerState.DoWork += RunFunction;
            WorkerState.RunWorkerCompleted += Completed;
        }

        private void DisposeWorker()
        {
            WorkerState.DoWork -= RunFunction;
            WorkerState.RunWorkerCompleted -= Completed; 
            WorkerState.Dispose();
        }

        private void RunFunction(object sender, DoWorkEventArgs e)
        {
            e.Result = _GetValue();
        }

        private void Completed(object sender, RunWorkerCompletedEventArgs e)
        {
            OnRunWorkerCompleted(e);
        }

        public override void Dispose()
        {
            DisposeWorker();
            base.Dispose();
        }
    }
}
